﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using CoreVirtuoso.Config;
using CoreVirtuoso.Helpers;
using Infrastructure.Events.Interfaces;
using Infrastructure.Helpers;
using VDS.RDF;
using VDS.RDF.Storage;
using VirtuosoDal.Config;
using VirtuosoDal.Entities;
using VirtuosoDal.Repositories.RdfRepositories.Events;
using VirtuosoDal.Repositories.RdfRepositories.Interfaces.Events;
using VirtuosoDal.Repositories.RdfRepositories.Interfaces.VirtuosoCore;

namespace Infrastructure.Events
{
   public class EventCrudService : IEventCrudService
   {
      private readonly ISequenceRepository _sequenceRepository;
      private readonly IGraphRepository _graphRepository;
      private readonly IEventsContentRepository _eventsContentRepository;

      public EventCrudService(ISequenceRepository sequenceRepository,
         IGraphRepository graphRepository,
         IEventsContentRepository eventsContentRepository)
      {
         _sequenceRepository = sequenceRepository;
         _eventsContentRepository = eventsContentRepository;
         _graphRepository = graphRepository;
      }

      public int CreateEvent(Event @event)
      {
         using (var virtuosoManager = new VirtuosoManager(ConnectionStringsHelper.GetVirtuosoConnectionString()))
         {
            return CreateEvent(virtuosoManager, @event, false);
         }
      }

      private int CreateEvent(VirtuosoManager virtuosoManager,
         Event @event,
         bool isEditing)
      {
         int eventId = -1;
         if (!isEditing) // creation
         {
            eventId = _sequenceRepository.SequenceNext(Sequences.EventsSequenceSet);
            @event.Uri = Namespaces.EventsContentNamespace + eventId;
         }

         var graph = new Graph();

         INode subject = graph.CreateUriNode(new Uri(@event.Uri));
         INode predicate = null;

         //Title
         graph.Assert(subject, graph.CreateUriNode(new Uri(EventsOntologyUris.TitlePropertyUri)), graph.CreateLiteralNode(@event.Title));

         //Description
         graph.Assert(subject, graph.CreateUriNode(new Uri(EventsOntologyUris.DescriptionPropertyUri)), graph.CreateLiteralNode(@event.Description));

         //Start datetime
         graph.Assert(subject, graph.CreateUriNode(new Uri(EventsOntologyUris.StartDateTimePropertyUri)), NodeHelper.CreateDateTimeOffsetNode(graph, @event.StartDateTimeOffset));

         //End datetime
         if (@event.EndDateTimeOffset.HasValue)
            graph.Assert(subject, graph.CreateUriNode(new Uri(EventsOntologyUris.EndDateTimePropertyUri)), NodeHelper.CreateDateTimeOffsetNode(graph, @event.EndDateTimeOffset.Value));

         if (@event.CityUri != null)
            graph.Assert(subject, graph.CreateUriNode(new Uri(EventsOntologyUris.CityPropertyUri)),
                         graph.CreateUriNode(new Uri(@event.CityUri)));

         if (@event.PlaceUri != null)
            graph.Assert(subject, graph.CreateUriNode(new Uri(EventsOntologyUris.PlacePropertyUri)), 
               graph.CreateUriNode(new Uri(@event.PlaceUri)));

         graph.Assert(subject, graph.CreateUriNode(new Uri(EventsOntologyUris.EventTypePropertyUri)), graph.CreateUriNode(new Uri(@event.Type)));

         foreach (var category in @event.Categories)
            graph.Assert(subject, graph.CreateUriNode(new Uri(EventsOntologyUris.EventCategoryPropertyUri)), graph.CreateUriNode(new Uri(category)));

         foreach (var additionalProperty in @event.AdditionalPropertiesWithValues.Keys)
             foreach (var additionalPropertyValue in @event.AdditionalPropertiesWithValues[additionalProperty])
                 //ToDo: It works only for Hierarchy properties - reimplement
                 graph.Assert(subject, 
                     graph.CreateUriNode(new Uri(additionalProperty)), 
                     graph.CreateUriNode(new Uri(additionalPropertyValue)));

         //LastEditing datetime
         graph.Assert(subject, graph.CreateUriNode(new Uri(EventsOntologyUris.LastEditingDateTimePropertyUri)), NodeHelper.CreateDateTimeNode(graph, @event.LastEditingDateTime));

         if (!isEditing)
         {
            //Creation datetime
            graph.Assert(subject, graph.CreateUriNode(new Uri(EventsOntologyUris.CreationDateTimePropertyUri)), NodeHelper.CreateDateTimeNode(graph, @event.CreationDateTime));

            //Creator
            graph.Assert(subject, graph.CreateUriNode(new Uri(EventsOntologyUris.CreatedByPropertyUri)), graph.CreateLiteralNode(@event.Creator));
         }

         _graphRepository.AddTriplesToGraph(virtuosoManager, Namespaces.EventsContentNamespace, new List<Triple>(graph.Triples));

         return eventId;
      }

      public void EditEvent(Event @event)
      {
         using (var virtuosoManager = new VirtuosoManager(ConnectionStringsHelper.GetVirtuosoConnectionString()))
         {
            virtuosoManager.Open(false);

            _eventsContentRepository.RemoveEventMetaData(virtuosoManager, @event.Uri);

            this.CreateEvent(virtuosoManager, @event, true);

            virtuosoManager.Close(true, false);
         }
      }
   }
}
